home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 February: Tool Chest / Dev.CD Feb 95 / Dev.CD Feb 95.toast / Tool Chest / QuickDraw GX / QuickDraw GX Info / QuickDraw GX Interfaces / Interfaces & Libraries / graphics libraries / layout edit library.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-30  |  32.8 KB  |  1,464 lines  |  [TEXT/MPS ]

  1. /*
  2.     layout edit library.c
  3.     
  4.     Simple layout editing based on the TextEdit model.
  5.     
  6.     Copyright ®1992, 1993 Apple Computer, Inc. All rights reserved.
  7. */
  8.  
  9.     #include <Types.h>
  10.     #include <Memory.h>
  11.     #include <Events.h>
  12.     #include <OSUtils.h>
  13.     #include <Scrap.h>
  14.     #include <Script.h>
  15.  
  16. #ifndef selectionLibraryIncludes
  17. #include "selection library.h"
  18. #endif
  19.  
  20. #ifndef layoutTypesIncludes
  21. #include "layout types.h"
  22. #endif
  23.  
  24. #ifndef layoutRoutinesIncludes
  25. #include "layout routines.h"
  26. #endif
  27.  
  28. #ifndef graphicsRoutinesIncludes
  29. #include "graphics routines.h"
  30. #endif
  31.  
  32. #include "graphics libraries.h"
  33.     #include "graphics toolbox.h"
  34. #include "storage library.h"
  35. #include "layout edit library.h"
  36.  
  37.  
  38. #define LockHandle(handle) (HLock ((Handle)handle), *handle)
  39. #define UnlockHandle(handle) HUnlock ((Handle)handle)
  40.  
  41. #define LockEditHandle(handle) (LayoutEditPtr) LockHandle(handle)
  42. #define UnlockEditHandle(handle) UnlockHandle(handle)
  43.  
  44. #define MIN(a,b) ((a) < (b)? (a): (b))
  45. #define MAX(a,b) ((a) > (b)? (a): (b))
  46.  
  47. #define maxRanges 10
  48. #define textBufferLength 16
  49. #define nextUpdateDelta 5
  50.  
  51. #define layoutOutOfDate 0x8000
  52. #define highlightOutOfDate 0x4000
  53.  
  54. #undef noFlicker
  55.  
  56. enum
  57. {    backSpace = 8,
  58.     leftArrow = 0x1C,
  59.     rightArrow,
  60.     upArrow,
  61.     downArrow
  62. };
  63.  
  64. typedef unsigned long ulong;
  65. typedef unsigned short ushort;
  66.  
  67. /*
  68.     The LayoutEditRecord contains the layout and highlight shapes,
  69.     the selection. flags contains flags which indicate that the
  70.     layout and highlight shapes haven't been rebuilt since their
  71.     corresponding data in the LayoutEditRecord has been changed.
  72.     
  73.     nextUpdate time, if non-zero tells the idle routine when to
  74.     update and re-draw the layout gxShape. 
  75.     
  76.     selectionRanges is working storage used for manipulating the
  77.     layout's selection. NOTE: the actual handle containing the
  78.     LayoutEditRecord will be large enough to contain the
  79.     SelectionOffsetRange array which immediately follows selectionRanges.
  80. */
  81. typedef struct {
  82.     short flags;
  83.     short highlightHideCount;
  84.     short    oldScript;
  85.     SelectionOffset synchOffset;
  86.     gxShape layout;
  87.     gxShape eraser;
  88.     gxShape highlight;
  89.     SelectionHandle selection;
  90.     gxShape scrap;
  91.     ulong nextUpdateTime;
  92.     long deleteStartOffset;
  93.     long deleteEndOffset;
  94.     gxStyle insertionStyle;
  95.     short insertionLevel;
  96.     short textBufferOffset;
  97.     char textBuffer[textBufferLength];
  98.     SelectionRanges selectionRanges;
  99. } LayoutEditRecord, *LayoutEditPtr;
  100.  
  101.  
  102. /*
  103.     I N T E R N A L   R O U T I N E S
  104. */
  105.  
  106.  
  107. /*
  108.     Draw the part of the layout which has changed.
  109. */
  110. static void DrawDifference(LayoutEditPtr layout)
  111. {    GXDrawShape(layout->eraser);
  112.     GXDrawShape(layout->layout);
  113. }
  114.  
  115. /*
  116.     Synch the keyboard to the font at the new selection.
  117. */
  118. static void SynchKeyboard(LayoutEditPtr layout)
  119. {
  120.     gxStyle selectionStyle;
  121.     gxFontPlatform platform;
  122.     gxFontScript script;
  123.     gxFontLanguage language;
  124.  
  125.     GXGetLayoutParts(
  126.         layout->layout,
  127.         layout->synchOffset, layout->synchOffset,
  128.         nil,
  129.         nil, nil, &selectionStyle,
  130.         nil, nil, nil);
  131.     
  132.     if (selectionStyle == nil)
  133.         selectionStyle = GXGetShapeStyle(layout->layout);
  134.         
  135.     platform = GXGetStyleEncoding(selectionStyle, &script, &language);
  136.     
  137.     switch (platform)
  138.     {
  139.         case gxUnicodePlatform:
  140.             break;
  141.         
  142.         case gxMacintoshPlatform:
  143.             if (script == gxNoScript)
  144.                 script = smRoman;
  145.             else
  146.                 script -= 1;
  147.  
  148.             if (language != gxNoLanguage && GetScript((short) script, smScriptLang) != language - 1)
  149.                 SetScript((short) script, smScriptLang, language - 1);
  150.             
  151.             if (GetEnvirons(smKeyScript) != script)    
  152.                 KeyScript((short) script);
  153.             break;
  154.             
  155.         default:
  156.             break;
  157.     }
  158. }
  159.  
  160. /*
  161.     Build a selection from start to end. If start and end are equal,
  162.     the selection will be a caret.
  163. */
  164. static void NewSelection(LayoutEditPtr layout, SelectionOffset start, SelectionOffset end)
  165. {
  166.     layout->selectionRanges.rangeCount = 1;
  167.     layout->selectionRanges.ranges[0].minOffset = start;
  168.     layout->selectionRanges.ranges[0].maxOffset = end;
  169.     
  170.     if (layout->selection)
  171.         DisposeSelection(layout->selection);
  172.         
  173.     layout->selection = NewRangeSelection(&layout->selectionRanges.ranges[0]);
  174.     
  175.     layout->synchOffset = start;
  176.     layout->flags |= highlightOutOfDate;
  177. }
  178.  
  179. /*
  180.     Update the layout's highlight gxShape if the selection's
  181.     changed since we last built it.
  182. */
  183. static void UpdateHighlight(LayoutEditPtr layout)
  184. {
  185.     if (layout->flags & highlightOutOfDate)
  186.     {
  187.         DisposeShapeAt(&layout->highlight);
  188.         
  189.         layout->highlight = GetLayoutSelection(
  190.             layout->layout,
  191.             layout->selection,
  192.             0,
  193.             gxHighlightAverageAngle,
  194.             gxSplitCaretType);
  195.  
  196.         SetShapeCommonTransfer(layout->highlight, gxHighlightMode);
  197.         SetShapeCommonColor(layout->highlight, gxWhite);
  198.             
  199.         DisposeStyleAt(&layout->insertionStyle);
  200.         layout->insertionLevel = -1;
  201.  
  202.         SynchKeyboard(layout);
  203.         layout->flags &= ~highlightOutOfDate;
  204.     }
  205. }
  206.  
  207. /*
  208.     Build a new selection from start to end, and a new highlight gxShape
  209.     that matches it.
  210. */
  211. static void NewSelectionAndHighlight(
  212.     LayoutEditPtr layout,
  213.     SelectionOffset start,
  214.     SelectionOffset end)
  215. {
  216.     NewSelection(layout, start, end);
  217.     UpdateHighlight(layout);
  218. }
  219.  
  220. /*
  221.     Return the offset of the glyph before the one at the specified
  222.     offset in the layout's text.
  223. */
  224. static SelectionOffset GetPreviousOffset(gxShape layout, SelectionOffset offset)
  225. {
  226.     ushort firstGlyph, secondGlyph;
  227.     gxLayoutOffsetState offsetState;
  228.     static SelectionOffset offsetStateSizes[] = {1, 1, 2, 2, 0};
  229.     
  230.     GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
  231.     
  232.     return offset - offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
  233. }
  234.  
  235. /*
  236.     Delete the text from the layout in the range specified by pRange.
  237. */
  238. static void DeleteRange(LayoutEditPtr layout, SelectionOffsetRange *pRange)
  239. {
  240.     if (layout->deleteStartOffset < 0)
  241.         layout->deleteEndOffset = pRange->maxOffset;
  242.         
  243.     layout->deleteStartOffset = pRange->minOffset;
  244.     layout->flags |= layoutOutOfDate;
  245. }
  246.  
  247.  
  248. /*
  249.     Delete the selected text from the layout. If the selection is a
  250.     caret, delete the character before the caret. Change the selection
  251.     to a caret just before the old selection.
  252. */
  253.  
  254. static void DeleteSelection(LayoutEditPtr layout)
  255. {    SelectionType selectionType = GetSelectionType(layout->selection);
  256.     SelectionOffset newCaret;
  257.  
  258.     switch (selectionType)
  259.     {    case emptySelection:
  260.             newCaret = 0;
  261.             break;
  262.         
  263.         case simpleCaret:
  264.         {    SelectionOffset caret = GetCaretSelection(layout->selection, nil);
  265.         
  266.             if(layout->textBufferOffset)
  267.             {    layout->textBufferOffset -= 1;
  268.                 newCaret = caret - 1;
  269.             }
  270.             else if (caret > 0)
  271.             {    SelectionOffsetRange range;
  272.                 SelectionOffset previous = GetPreviousOffset(layout->layout, caret);
  273.             
  274.                 range.minOffset = newCaret = previous;
  275.                 range.maxOffset = caret;
  276.                 DeleteRange(layout, &range);
  277.             }
  278.             else newCaret = caret;
  279.             
  280.         break;
  281.         }
  282.         
  283.         case simpleRange:
  284.         case discontiguousRange:
  285.         {    long rangeCount;
  286.             SelectionRanges *ranges = &layout->selectionRanges;
  287.             SelectionOffsetRange *pRange;
  288.             
  289.             (void) GetRangeSelection(layout->selection, ranges);
  290.             rangeCount = ranges->rangeCount;
  291.             pRange = &ranges->ranges[rangeCount];
  292.             
  293.             /*
  294.                 go through the ranges backwards to save sliding stuff
  295.                 that'll get deleted later and so that the caret is set
  296.                 for the first range.
  297.             */
  298.             while (--rangeCount >= 0)
  299.             {    DeleteRange(layout, --pRange);
  300.                 newCaret = pRange->minOffset;
  301.             }
  302.                 
  303.             break;
  304.         }
  305.         
  306.     }
  307.     
  308.     /* set layout's selection to a caret before the deletion */
  309.     NewSelection(layout, newCaret, newCaret);
  310. }
  311.  
  312. /*
  313.     Make sure the handle is at least newSize bytes long;
  314.     If it isn't, grow it to be newSize + extra.
  315. */
  316. static Ptr GrowAndLockHandle(Handle handle, Size newSize, Size extra)
  317. {    Size oldSize = GetHandleSize(handle);
  318.  
  319.     if (oldSize < newSize) SetHandleSize(handle, newSize + extra);
  320.     return LockHandle(handle);
  321. }
  322.  
  323. static void SetEraser(LayoutEditPtr layout)
  324. {    layout->eraser = GXCopyToShape(layout->eraser, layout->layout);
  325.     SetShapeCommonColor(layout->eraser, gxWhite);
  326. }
  327.  
  328. /*
  329.     If the backing store in the LayoutEditRecord has changed since
  330.     the layout gxShape was last built, rebuild the layout.
  331. */
  332. static void UpdateLayout(LayoutEditPtr layout)
  333. {    if (layout->flags & layoutOutOfDate)
  334.     {    void *textBuffer = &layout->textBuffer, **text = nil;
  335.         short *levels = nil, levelRunCount = 0, styleRunCount = 0, textRunCount = 0,
  336.                     *textRunLength = nil, *styleRunLength = nil, *levelRunLength = nil;
  337.         gxStyle *styles = nil;
  338.         
  339.         SetEraser(layout);
  340.         
  341.         if (layout->textBufferOffset)
  342.         {    text = &textBuffer;
  343.             textRunLength = &layout->textBufferOffset;
  344.             textRunCount = 1;
  345.             
  346.             if (layout->insertionStyle)
  347.             {    styles = &layout->insertionStyle;
  348.                 styleRunLength = textRunLength;
  349.                 styleRunCount = 1;
  350.             }
  351.             
  352.             if (layout->insertionLevel >= 0)
  353.             {    levels = &layout->insertionLevel;
  354.                 levelRunLength = textRunLength;
  355.                 levelRunCount = 1;
  356.             }
  357.         }
  358.         
  359.         /* edit the layout */ 
  360.         GXSetLayoutParts(
  361.             layout->layout,
  362.             layout->deleteStartOffset,
  363.             layout->deleteEndOffset,
  364.             textRunCount,
  365.             textRunLength,
  366.             (const void **) text,
  367.             styleRunCount,
  368.             styleRunLength,
  369.             styles,
  370.             levelRunCount,
  371.             levelRunLength,
  372.             levels);
  373.         
  374.         /* erase the old layout and draw the new one */
  375.         DrawDifference(layout);
  376.  
  377.         layout->flags &= ~layoutOutOfDate;
  378.         layout->nextUpdateTime = 0;
  379.         layout->textBufferOffset = 0;
  380.         layout->deleteStartOffset = -1;
  381.         layout->insertionLevel = -1;
  382.         DisposeStyleAt(&layout->insertionStyle);
  383.     }
  384. }
  385.  
  386. /*
  387.     Add a character to the layout at the selection. This routine
  388.     assumes that the selection is a caret; i.e. if it was a range,
  389.     the range has been deleted leaving a caret.
  390. */
  391. static void InsertByte(LayoutEditPtr layout, char byte)
  392. {
  393.     SelectionOffset caret;
  394.  
  395.     caret = layout->selectionRanges.ranges[0].minOffset;
  396.     
  397.     if (layout->textBufferOffset >= textBufferLength)
  398.         UpdateLayout(layout);
  399.     
  400.     if (layout->deleteStartOffset < 0)
  401.         layout->deleteStartOffset = layout->deleteEndOffset = caret;
  402.         
  403.     layout->textBuffer[layout->textBufferOffset++] = byte;
  404.     
  405.     /* set selection to a caret after the new byte */
  406.     NewSelection(layout, caret + 1, caret + 1);
  407.     
  408.     layout->flags |= layoutOutOfDate;
  409. }
  410.  
  411. /*
  412.     If the highlight gxShape isn't already hidden, erase
  413.     it by drawing it on top of itself.
  414. */
  415. static void HideHighlight(LayoutEditPtr layout)
  416. {    if (layout->highlightHideCount++ == 0)
  417.         GXDrawShape(layout->highlight);
  418. }
  419.  
  420. /*
  421.     If the highlight gxShape isn't already visible, update it
  422.     and draw it.
  423. */
  424. static void ShowHighlight(LayoutEditPtr layout)
  425. {    if (--layout->highlightHideCount <= 0)
  426.     {    UpdateHighlight(layout);
  427.         GXDrawShape(layout->highlight);
  428.         layout->highlightHideCount = 0;
  429.     }
  430. }
  431.  
  432. static void DrawChangedLayout(LayoutEditPtr layout)
  433. {    HideHighlight(layout);
  434.         
  435.     DrawDifference(layout);
  436.     
  437.     layout->flags |= highlightOutOfDate;
  438.     ShowHighlight(layout);
  439. }
  440.  
  441. static void CopySelection(LayoutEditPtr layout)
  442. {    SelectionType selectionType = GetSelectionType(layout->selection);
  443.  
  444.     switch (selectionType)
  445.     {    case emptySelection:
  446.         case simpleCaret:
  447.         case discontiguousRange:
  448.             break;
  449.         
  450.         case simpleRange:
  451.         {    SelectionRanges *ranges = &layout->selectionRanges;
  452.             SelectionOffsetRange *pRange;
  453.             
  454.             (void) GetRangeSelection(layout->selection, ranges);
  455.             pRange = ranges->ranges;
  456.  
  457.             layout->scrap = GXGetLayoutShapeParts(layout->layout, pRange->minOffset, pRange->maxOffset, layout->scrap);                
  458.  
  459.             break;
  460.         }
  461.     }
  462. }
  463.  
  464. static void PasteSelection(LayoutEditPtr layout)
  465. {    SelectionType selectionType = GetSelectionType(layout->selection);
  466.     SelectionOffset newCaret, startOffset, endOffset;
  467.     
  468.     SetEraser(layout);
  469.  
  470.     switch (selectionType)
  471.     {    case emptySelection:
  472.         case discontiguousRange:
  473.             return;
  474.     
  475.         case simpleCaret:
  476.             newCaret = startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  477.             break;
  478.         
  479.         case simpleRange:
  480.         {    SelectionRanges *ranges = &layout->selectionRanges;
  481.             
  482.             (void) GetRangeSelection(layout->selection, ranges);
  483.             startOffset = ranges->ranges[0].minOffset;
  484.             endOffset = ranges->ranges[0].maxOffset;
  485.             newCaret = startOffset;
  486.             
  487.             
  488.             break;
  489.         }
  490.  
  491.     }
  492.     newCaret += GXGetLayout(layout->scrap, nil, 0, nil, nil, 0, nil, nil, nil, nil);
  493.     GXSetLayoutShapeParts(layout->layout, startOffset, endOffset, layout->scrap);
  494.     DrawDifference(layout);
  495.     NewSelection(layout, newCaret, newCaret);
  496. }
  497.  
  498. static void AdjustSelectedLevels(LayoutEditPtr layout, short levelAdjust)
  499. {    short *lengths, *levels;
  500.     long levelRunCount;
  501.     SelectionType selectionType = GetSelectionType(layout->selection);
  502.     SelectionRanges *ranges = &layout->selectionRanges;
  503.     SelectionOffset startOffset, endOffset;
  504.     
  505.     UpdateLayout(layout);
  506.     
  507.     switch (selectionType)
  508.     {    case emptySelection:
  509.         case discontiguousRange:
  510.             return;
  511.             
  512.         case simpleCaret:
  513.             startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  514.             break;
  515.         
  516.         case simpleRange:
  517.         {    SelectionRanges *ranges = &layout->selectionRanges;
  518.         
  519.             GetRangeSelection(layout->selection, ranges);
  520.             startOffset = ranges->ranges[0].minOffset;
  521.             endOffset = ranges->ranges[0].maxOffset;
  522.         }
  523.         break;
  524.     }
  525.     
  526.     GXGetLayoutParts(layout->layout, startOffset, endOffset, nil, nil, nil, nil, &levelRunCount, nil, nil);
  527.     
  528.     levels = (short *) NewPtr(levelRunCount * sizeof(short));
  529.     lengths = (short *) NewPtr(levelRunCount * sizeof(short));
  530.     
  531.     GXGetLayoutParts(layout->layout, startOffset, endOffset, nil, nil, nil, nil, nil, lengths, levels);
  532.     
  533.     if (startOffset == endOffset) layout->insertionLevel = MAX(*levels + levelAdjust, 0);
  534.     else
  535.     {    short i, length = endOffset - startOffset, *pl;
  536.     
  537.         SetEraser(layout);
  538.         
  539.         for (pl = levels, i = levelRunCount - 1; i >= 0; --i, ++pl)
  540.             *pl = MAX(*pl + levelAdjust, 0);
  541.  
  542.         
  543.         GXSetLayoutParts(
  544.             layout->layout,
  545.             startOffset,
  546.             endOffset,
  547.             0,
  548.             nil,
  549.             nil,
  550.             0,
  551.             nil,
  552.             nil,
  553.             levelRunCount,
  554.             lengths,
  555.             levels);
  556.             
  557.         HideHighlight(layout);
  558.         DrawDifference(layout);
  559.         ShowHighlight(layout);
  560.         
  561.         layout->insertionLevel = -1;
  562.     }
  563.     
  564.     DisposePtr((Ptr) lengths);
  565.     DisposePtr((Ptr) levels);
  566. }
  567.  
  568.  
  569. /*
  570.     P U B L I C   R O U T I N E S
  571. */
  572.  
  573. LayoutEditHandle LayoutEditHandleFromLayout(gxShape layoutShape)
  574. {    LayoutEditHandle handle;
  575.     LayoutEditPtr layout;
  576.  
  577.     /* SetShapeFastXorTransfer(layoutShape, nil, nil); */
  578.     
  579.     handle = (LayoutEditHandle) NewHandle(
  580.         sizeof(LayoutEditRecord) + maxRanges * sizeof(SelectionOffsetRange));
  581.     
  582.     layout = LockEditHandle(handle);
  583.     layout->layout = layoutShape;
  584.     layout->eraser = nil;
  585.     layout->flags = 0;
  586.     layout->selection = nil;
  587.     layout->highlight = nil;
  588.     layout->scrap = nil;
  589.     layout->highlightHideCount = 0;
  590.     layout->nextUpdateTime = 0;
  591.     layout->textBufferOffset = 0;
  592.     layout->insertionStyle = nil;
  593.     layout->insertionLevel = -1;
  594.     layout->deleteStartOffset = -1;
  595.     
  596.     /* set the initial selection to a caret before the first character */
  597.     NewSelectionAndHighlight(layout, 0, 0);
  598.         
  599.     UnlockHandle(handle);
  600.     
  601.     return handle;
  602. }
  603.  
  604. LayoutEditHandle NewLayoutEditHandle(
  605.     long textRunCount,
  606.     const short textRunLengths[],
  607.     const void *text[],
  608.     long styleRunCount,
  609.     const short styleRunLengths[],
  610.     const gxStyle styles[],
  611.     long levelRunCount,
  612.     const short levelRunLengths[],
  613.     const short levels[],
  614.     gxLayoutOptions *layoutOptions,
  615.     gxPoint *position,
  616.     gxStyle defaultStyle)
  617. {    gxShape layoutShape;
  618.     
  619.     /* just call GXNewLayout for param error checking */
  620.     layoutShape = GXNewLayout(
  621.         textRunCount,
  622.         textRunLengths,
  623.         text,
  624.         styleRunCount,
  625.         styleRunLengths,
  626.         styles,
  627.         levelRunCount,
  628.         levelRunLengths,
  629.         levels,
  630.         layoutOptions,
  631.         position);
  632.     
  633.     /* If GXNewLayout posts an error, we won't get here... */
  634.  
  635.     if (defaultStyle) GXSetShapeStyle(layoutShape, defaultStyle);
  636.     return LayoutEditHandleFromLayout(layoutShape);
  637. }
  638.  
  639. long GetLayoutEditHandle(
  640.     LayoutEditHandle handle,
  641.     void *text,
  642.     long *styleRunCount,
  643.     short styleRunLengths[],
  644.     gxStyle styles[],
  645.     long *levelRunCount,
  646.     short levelRunLengths[],
  647.     short levels[],
  648.     gxLayoutOptions *layoutOptions,
  649.     gxPoint *position)
  650. {    LayoutEditPtr layout = LockEditHandle(handle);
  651.     long result;
  652.     
  653.     UpdateLayout(layout);
  654.     
  655.     result = GXGetLayout(
  656.         layout->layout,
  657.         text,
  658.         styleRunCount,
  659.         styleRunLengths,
  660.         styles,
  661.         levelRunCount,
  662.         levelRunLengths,
  663.         levels,
  664.         layoutOptions,
  665.         position);
  666.     
  667.     UnlockHandle(handle);
  668.     
  669.     return result;
  670. }
  671.  
  672. void SetLayoutEditHandle(
  673.     LayoutEditHandle handle,
  674.     long textRunCount,
  675.     const short textRunLengths[],
  676.     const void *text[],
  677.     long styleRunCount,
  678.     const short styleRunLengths[],
  679.     const gxStyle styles[],
  680.     long levelRunCount,
  681.     const short levelRunLengths[],
  682.     const short levels[],
  683.     const gxLayoutOptions *layoutOptions,
  684.     const gxPoint *position)
  685. {    LayoutEditPtr layout = LockEditHandle(handle);
  686.     
  687.     SetEraser(layout);
  688.  
  689.     UpdateLayout(layout);
  690.     
  691.     GXSetLayout(
  692.         layout->layout,
  693.         textRunCount,
  694.         textRunLengths,
  695.         text,
  696.         styleRunCount,
  697.         styleRunLengths,
  698.         styles,
  699.         levelRunCount,
  700.         levelRunLengths,
  701.         levels,
  702.         layoutOptions,
  703.         position);
  704.     
  705.     DrawChangedLayout(layout);
  706.     
  707.     UnlockHandle(handle);
  708. }
  709.  
  710. void SetLayoutEditHandleParts(
  711.     LayoutEditHandle handle,
  712.     gxByteOffset oldStartOffset,
  713.     gxByteOffset oldEndOffset,
  714.     long newTextRunCount,
  715.     const short newTextRunLengths[],
  716.     const void *newText[],
  717.     long newStyleRunCount,
  718.     const short newStyleRunLengths[],
  719.     const gxStyle newStyles[],
  720.     long newLevelRunCount,
  721.     const short newLevelRunLengths[],
  722.     const short newLevels[])
  723. {    LayoutEditPtr layout = LockEditHandle(handle);
  724.     
  725.     SetEraser(layout);
  726.  
  727.     UpdateLayout(layout);
  728.     
  729.     GXSetLayoutParts(
  730.         layout->layout,
  731.         oldStartOffset,
  732.         oldEndOffset,
  733.         newTextRunCount,
  734.         newTextRunLengths,
  735.         newText,
  736.         newStyleRunCount,
  737.         newStyleRunLengths,
  738.         newStyles,
  739.         newLevelRunCount,
  740.         newLevelRunLengths,
  741.         newLevels);
  742.     
  743.     DrawChangedLayout(layout);
  744.     
  745.     UnlockHandle(handle);
  746. }
  747.  
  748. void SetLayoutEditHandleSelectedParts(
  749.     LayoutEditHandle handle,
  750.     long newTextRunCount,
  751.     const short newTextRunLengths[],
  752.     const void *newText[],
  753.     long newStyleRunCount,
  754.     const short newStyleRunLengths[],
  755.     const gxStyle newStyles[],
  756.     long newLevelRunCount,
  757.     const short newLevelRunLengths[],
  758.     const short newLevels[])
  759. {
  760.     LayoutEditPtr layout;
  761.     SelectionOffset startOffset, endOffset;
  762.     
  763.     layout = LockEditHandle(handle);
  764.     UpdateLayout(layout);
  765.     
  766.     DisposeStyleAt(&layout->insertionStyle);
  767.     layout->insertionLevel = -1;
  768.                     
  769.     switch (GetSelectionType(layout->selection))
  770.     {
  771.         case emptySelection:
  772.         case discontiguousRange:
  773.             /* should never happen */
  774.             break;
  775.             
  776.         case simpleCaret:
  777.             startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  778.  
  779.             if (newTextRunCount == 0)
  780.             {
  781.                 if (newStyleRunCount == 1 && newStyleRunLengths[0] == 0)
  782.                 {
  783.                     layout->insertionStyle = GXCloneStyle(newStyles[0]);
  784.                     newStyleRunCount = 0;
  785.                     newStyleRunLengths = nil;
  786.                     newStyles = nil;
  787.                 }
  788.                 
  789.                 if (newLevelRunCount == 1 && newLevelRunLengths[0] == 0)
  790.                 {
  791.                     layout->insertionLevel = newLevels[0];
  792.                     newLevelRunCount = 0;
  793.                     newLevelRunLengths = nil;
  794.                     newLevels = nil;
  795.                 }
  796.             }
  797.                 
  798.             break;
  799.             
  800.         case simpleRange:
  801.         {
  802.             SelectionRanges *ranges = &layout->selectionRanges;
  803.         
  804.             (void) GetRangeSelection(layout->selection, ranges);
  805.             
  806.             startOffset = ranges->ranges[0].minOffset;
  807.             endOffset = ranges->ranges[0].maxOffset;
  808.             
  809.             break;
  810.         }
  811.     }
  812.  
  813.         
  814.     if (newTextRunCount > 0 || newStyleRunCount > 0 || newLevelRunCount > 0)
  815.     {            
  816.         SetEraser(layout);
  817.     
  818.         GXSetLayoutParts(
  819.             layout->layout,
  820.             startOffset,
  821.             endOffset,
  822.             newTextRunCount, newTextRunLengths, newText,
  823.             newStyleRunCount, newStyleRunLengths, newStyles,
  824.             newLevelRunCount, newLevelRunLengths, newLevels);
  825.  
  826.         DrawChangedLayout(layout);
  827.     }
  828.         
  829.     UnlockEditHandle(handle);
  830. }
  831.  
  832. void SetLayoutEditHandleShapeParts(
  833.     LayoutEditHandle handle,
  834.     gxByteOffset startOffset,
  835.     gxByteOffset endOffset,
  836.     gxShape insert)
  837. {    LayoutEditPtr layout = LockEditHandle(handle);
  838.     
  839.     SetEraser(layout);
  840.  
  841.     UpdateLayout(layout);
  842.     
  843.     GXSetLayoutShapeParts(
  844.         layout->layout,
  845.         startOffset,
  846.         endOffset,
  847.         insert);
  848.     
  849.     DrawChangedLayout(layout);
  850.     
  851.     UnlockHandle(handle);
  852. }
  853.  
  854. long GetLayoutEditHandleParts(
  855.     LayoutEditHandle handle,
  856.     gxByteOffset startOffset,
  857.     gxByteOffset endOffset,
  858.     void *text,
  859.     long *styleRunCount,
  860.     short styleRunLengths[],
  861.     gxStyle styles[],
  862.     long *levelRunCount,
  863.     short levelRunLengths[],
  864.     short levels[])
  865. {    LayoutEditPtr layout = LockEditHandle(handle);
  866.     long result;
  867.     
  868.     UpdateLayout(layout);
  869.     
  870.     result = GXGetLayoutParts(
  871.         layout->layout,
  872.         startOffset,
  873.         endOffset,
  874.         text,
  875.         styleRunCount,
  876.         styleRunLengths,
  877.         styles,
  878.         levelRunCount,
  879.         levelRunLengths,
  880.         levels);
  881.     
  882.     UnlockHandle(handle);
  883.     return result;
  884. }
  885.  
  886. long GetLayoutEditHandleSelectedParts(
  887.     LayoutEditHandle handle,
  888.     void *text,
  889.     long *styleRunCount,
  890.     short styleRunLengths[],
  891.     gxStyle styles[],
  892.     long *levelRunCount,
  893.     short levelRunLengths[],
  894.     short levels[])
  895. {
  896.     SelectionType selectionType;
  897.     gxByteOffset endOffset, startOffset;
  898.     LayoutEditPtr layout;
  899.     long result;
  900.     
  901.     layout = LockEditHandle(handle);
  902.     UpdateLayout(layout);
  903.     selectionType = GetSelectionType(layout->selection);
  904.     
  905.     switch (selectionType)
  906.     {    case emptySelection:
  907.         case discontiguousRange:
  908.             /* should never happen */
  909.             break;
  910.             
  911.         case simpleCaret:
  912.         
  913.             startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  914.  
  915.             if (styles != nil && layout->insertionStyle != nil)
  916.             {
  917.                 *styles = layout->insertionStyle;
  918.                 styles = nil;
  919.             }
  920.             
  921.             if (levels != nil && layout->insertionLevel >= 0)
  922.             {
  923.                 *levels = layout->insertionLevel;
  924.                 levels = nil;
  925.             }
  926.  
  927.             break;
  928.             
  929.         case simpleRange:
  930.         {    SelectionRanges *ranges = &layout->selectionRanges;
  931.             short length;
  932.                     
  933.             (void) GetRangeSelection(layout->selection, ranges);
  934.             
  935.             startOffset = ranges->ranges[0].minOffset;
  936.             endOffset = ranges->ranges[0].maxOffset;
  937.         }
  938.     }
  939.             
  940.     result = GXGetLayoutParts(
  941.         layout->layout,
  942.         startOffset,
  943.         endOffset,
  944.         text,
  945.         styleRunCount,
  946.         styleRunLengths,
  947.         styles,
  948.         levelRunCount,
  949.         levelRunLengths,
  950.         levels);
  951.     
  952.     UnlockHandle(handle);
  953.     return result;
  954. }
  955.  
  956. gxShape GetLayoutEditHandleShapeParts(
  957.     LayoutEditHandle handle,
  958.     gxByteOffset startOffset,
  959.     gxByteOffset endOffset,
  960.     gxShape dest)
  961. {    LayoutEditPtr layout = LockEditHandle(handle);
  962.     gxShape result;
  963.     
  964.     UpdateLayout(layout);
  965.     
  966.     result = GXGetLayoutShapeParts(layout->layout, startOffset, endOffset, dest);
  967.     
  968.     UnlockHandle(handle);
  969.     return result;
  970. }
  971.  
  972. void LayoutEditRotateShape(LayoutEditHandle handle, fixed degrees, fixed translateX, fixed translateY)
  973. {
  974.     LayoutEditPtr layout;
  975.     
  976.     layout = LockEditHandle(handle);
  977.     
  978.     UpdateLayout(layout);
  979.  
  980.     SetEraser(layout);
  981.     
  982.     GXRotateShape(layout->layout, degrees, translateX, translateY);
  983.     
  984.     DrawChangedLayout(layout);
  985.     
  986.     UnlockEditHandle(handle);
  987. }
  988.  
  989. void LayoutEditIdle(LayoutEditHandle handle)
  990. {    ulong ticks = TickCount();
  991.     ulong next = ((LayoutEditPtr) *handle)->nextUpdateTime;
  992.     
  993.     if (next && ticks >= next)
  994.     {    LayoutEditPtr layout = LockEditHandle(handle);
  995.         
  996.         HideHighlight(layout);
  997.         UpdateLayout(layout);
  998.         ShowHighlight(layout);
  999.         
  1000.         UnlockEditHandle(handle);
  1001.     }
  1002. }
  1003.  
  1004. void LayoutEditClick(LayoutEditHandle handle, gxPoint hitDown)
  1005. {    LayoutEditPtr layout = LockEditHandle(handle); 
  1006.     gxPoint lastPoint = hitDown;
  1007.     SelectionOffset firstHitOffset, lastHitOffset;
  1008.     gxLayoutHitInfo hitInfo;
  1009.     boolean oldIsCaret, newIsCaret = true;
  1010.     gxShape diffHighlight = nil, oldHighlight = nil;
  1011.     gxViewPort layoutViewPort = GetShapeViewPort(layout->layout);
  1012.  
  1013.     /* get the offset for the hit down gxPoint */
  1014.     GXHitTestLayout(layout->layout, &hitDown, gxHighlightAverageAngle, &hitInfo, nil);
  1015.     firstHitOffset = lastHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1016.     
  1017.     /* erase the old highlight */
  1018.     GXDrawShape(layout->highlight);
  1019.  
  1020.     /* Make the selection a caret at firstHitOffset */
  1021.     NewSelectionAndHighlight(layout, firstHitOffset, firstHitOffset);
  1022.     GXDrawShape(layout->highlight);
  1023.  
  1024.     /* recompute the selection and highlight while the mouse button is still down */
  1025.     while (Button())
  1026.     {    GXGetViewPortMouse(layoutViewPort, &hitDown);
  1027.     
  1028.         /* continue if the mouse hasn't moved */
  1029.         if (hitDown.x == lastPoint.x && hitDown.y == lastPoint.y) continue;
  1030.         
  1031.         lastPoint = hitDown;
  1032.         GXHitTestLayout(layout->layout, &hitDown, gxHighlightAverageAngle, &hitInfo, nil);
  1033.         
  1034.         /* continue if the selection hasn't changed */
  1035.         if (hitInfo.hitSideOffset == lastHitOffset) continue;
  1036.         
  1037.         oldIsCaret = newIsCaret;
  1038.  
  1039.         /* save the old highlight and calculate the new one */
  1040.         lastHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1041.         newIsCaret = (lastHitOffset == firstHitOffset);
  1042.         
  1043.         if (oldIsCaret != newIsCaret)
  1044.         {    GXDrawShape(layout->highlight);
  1045.             NewSelectionAndHighlight(layout, firstHitOffset, lastHitOffset);
  1046.             GXDrawShape(layout->highlight);
  1047.         }
  1048.         else
  1049.         {    oldHighlight = GXCopyToShape(oldHighlight, layout->highlight);
  1050.             NewSelectionAndHighlight(layout, firstHitOffset, lastHitOffset);
  1051.         
  1052.             /* to reduce flicker, draw the difference between the new and old highlight */
  1053.             diffHighlight = GXCopyToShape(diffHighlight, layout->highlight);
  1054.             GXExcludeShape(diffHighlight, oldHighlight);
  1055.             GXDrawShape(diffHighlight);
  1056.         }
  1057.     }
  1058.  
  1059.     DisposeShapeAt(&diffHighlight);
  1060.     DisposeShapeAt(&oldHighlight);
  1061. }
  1062.  
  1063.  
  1064. void LayoutEditActivate(LayoutEditHandle handle)
  1065. {    LayoutEditPtr layout = LockEditHandle(handle);
  1066.  
  1067.     if (layout->oldScript != GetEnvirons(smKeyScript))
  1068.         KeyScript(layout->oldScript);
  1069.         
  1070.     UpdateLayout(layout);
  1071.     ShowHighlight(layout);
  1072.     UnlockEditHandle(handle);
  1073. }
  1074.  
  1075.  
  1076. void LayoutEditDeactivate(LayoutEditHandle handle)
  1077. {    LayoutEditPtr layout = LockEditHandle(handle);
  1078.  
  1079.     layout->oldScript = GetEnvirons(smKeyScript);
  1080.     
  1081.     HideHighlight(layout);
  1082.     UnlockEditHandle(handle);
  1083. }
  1084.  
  1085.  
  1086. void LayoutEditKey(LayoutEditHandle handle, char key)
  1087. {    LayoutEditPtr layout = LockEditHandle(handle);
  1088.  
  1089.     switch (key)
  1090.     {    case leftArrow:
  1091.         case rightArrow:
  1092.         {    SelectionOffset newCaret; 
  1093.         
  1094.             HideHighlight(layout);
  1095.             UpdateLayout(layout);
  1096.             
  1097.             if (key == leftArrow)
  1098.                 newCaret = GXGetLeftVisualOffset(
  1099.                     layout->layout,
  1100.                     layout->selectionRanges.ranges[0].minOffset);
  1101.             else newCaret = GXGetRightVisualOffset(
  1102.                 layout->layout,
  1103.                 layout->selectionRanges.ranges[0].maxOffset);
  1104.             
  1105.             NewSelection(layout, newCaret, newCaret);
  1106.             ShowHighlight(layout);
  1107.             break;
  1108.         }
  1109.         
  1110.         case backSpace:
  1111.         {
  1112.             DeleteSelection(layout);
  1113.             if (layout->nextUpdateTime == 0)
  1114.                 layout->nextUpdateTime = TickCount() + nextUpdateDelta;
  1115.             break;
  1116.         }
  1117.         
  1118.         default:
  1119.         {    
  1120.         
  1121.             switch (GetSelectionType(layout->selection))
  1122.             {    case emptySelection:
  1123.                     break;
  1124.                 
  1125.                 case discontiguousRange:
  1126.                 case simpleRange:
  1127.                     DeleteSelection(layout);
  1128.                 
  1129.                 case simpleCaret:
  1130.                     InsertByte(layout, key);
  1131.                     if (layout->nextUpdateTime == 0)
  1132.                         layout->nextUpdateTime = TickCount() + nextUpdateDelta;
  1133.             }
  1134.         }
  1135.     }
  1136.     
  1137.     UnlockEditHandle(handle);
  1138. }
  1139.  
  1140.  
  1141. void LayoutEditUpdate(LayoutEditHandle handle)
  1142. {    LayoutEditPtr layout = LockEditHandle(handle);
  1143.  
  1144.     GXDrawShape(layout->layout);
  1145.     ShowHighlight(layout);
  1146.     
  1147.     UnlockEditHandle(handle);
  1148. }
  1149.  
  1150.  
  1151. SelectionHandle LayoutEditGetSelection(LayoutEditHandle handle)
  1152. {  LayoutEditPtr layout = (LayoutEditPtr) LockHandle(handle);
  1153.    SelectionHandle selection;
  1154.  
  1155.    UpdateLayout(layout);
  1156.    selection = layout->selection;
  1157.    UnlockEditHandle(handle);
  1158.  
  1159.    return selection;
  1160. }
  1161.  
  1162. void LayoutEditSetSelection(LayoutEditHandle handle, SelectionOffset start, SelectionOffset end)
  1163. {    LayoutEditPtr layout = LockEditHandle(handle);
  1164.  
  1165.     UpdateLayout(layout);
  1166.     
  1167.     HideHighlight(layout);
  1168.     NewSelection(layout, start, end);
  1169.     ShowHighlight(layout);
  1170.     
  1171.     UnlockEditHandle(handle);
  1172. }
  1173.  
  1174. void LayoutEditSetSelectionHandle(LayoutEditHandle handle, SelectionHandle selection)
  1175. {    SelectionOffset end, start;
  1176.  
  1177.     switch (GetSelectionType(selection))
  1178.     {    case emptySelection:
  1179.         case discontiguousRange:
  1180.             return;
  1181.             
  1182.         case simpleCaret:
  1183.             start = end = GetCaretSelection(selection, nil);
  1184.             break;
  1185.         
  1186.         case simpleRange:
  1187.         {    SelectionRanges ranges;
  1188.         
  1189.             (void) GetRangeSelection(selection, &ranges);
  1190.             start = ranges.ranges[0].minOffset;
  1191.             end = ranges.ranges[0].maxOffset;
  1192.             break;
  1193.         }
  1194.     }
  1195.     
  1196.     LayoutEditSetSelection(handle, start, end);
  1197. }
  1198.  
  1199. gxViewPort GetLayoutEditViewPort(LayoutEditHandle handle)
  1200. {    LayoutEditPtr layout = LockEditHandle(handle);
  1201.     gxViewPort viewPort = GetShapeViewPort(layout->layout);
  1202.     
  1203.     UnlockEditHandle(handle);
  1204.     return viewPort;
  1205. }
  1206.  
  1207. void LayoutEditSetStyle(LayoutEditHandle handle, gxStyle newStyle)
  1208. {    LayoutEditPtr layout = LockEditHandle(handle);
  1209.     SelectionType selectionType = GetSelectionType(layout->selection);
  1210.     
  1211.     UpdateLayout(layout);
  1212.     
  1213.     DisposeStyleAt(&layout->insertionStyle);
  1214.                     
  1215.     switch (selectionType)
  1216.     {    case emptySelection:
  1217.         case discontiguousRange:
  1218.             /* should never happen */
  1219.             break;
  1220.             
  1221.         case simpleCaret:
  1222.             layout->insertionStyle = GXCloneStyle(newStyle);
  1223.             break;
  1224.             
  1225.         case simpleRange:
  1226.         {    SelectionRanges *ranges = &layout->selectionRanges;
  1227.             SelectionOffset startOffset, endOffset;
  1228.             short length;
  1229.         
  1230.             SetEraser(layout);
  1231.             
  1232.             (void) GetRangeSelection(layout->selection, ranges);
  1233.             
  1234.             startOffset = ranges->ranges[0].minOffset;
  1235.             endOffset = ranges->ranges[0].maxOffset;
  1236.             length = endOffset - startOffset;
  1237.             
  1238.             GXSetLayoutParts(
  1239.                 layout->layout,
  1240.                 startOffset,
  1241.                 endOffset,
  1242.                 0,
  1243.                 nil,
  1244.                 nil,
  1245.                 1,
  1246.                 &length,
  1247.                 &newStyle,
  1248.                 0,
  1249.                 nil,
  1250.                 nil);
  1251.                 
  1252.             DrawChangedLayout(layout);
  1253.  
  1254.             break;
  1255.         }
  1256.     }
  1257.  
  1258.     UnlockEditHandle(handle);
  1259. }
  1260.  
  1261. void LayoutEditIncrementLevel(LayoutEditHandle handle)
  1262. {    LayoutEditPtr layout = LockEditHandle(handle);
  1263.  
  1264.     HideHighlight(layout);
  1265.     AdjustSelectedLevels(layout, 1);
  1266.     layout->flags |= highlightOutOfDate;
  1267.     ShowHighlight(layout);
  1268.     
  1269.     UnlockEditHandle(handle);
  1270. }
  1271.  
  1272. void LayoutEditDecrementLevel(LayoutEditHandle handle)
  1273. {    LayoutEditPtr layout = LockEditHandle(handle);
  1274.  
  1275.     HideHighlight(layout);
  1276.     AdjustSelectedLevels(layout, -1);
  1277.     layout->flags |= highlightOutOfDate;
  1278.     ShowHighlight(layout);
  1279.     
  1280.     UnlockEditHandle(handle);
  1281. }
  1282.  
  1283. void LayoutEditSetLevel(LayoutEditHandle handle, long level)
  1284. {    LayoutEditPtr layout = LockEditHandle(handle);
  1285.     SelectionType selectionType = GetSelectionType(layout->selection);
  1286.     short newLevel = level;
  1287.     
  1288.     UpdateLayout(layout);
  1289.     
  1290.     switch (selectionType)
  1291.     {    case emptySelection:
  1292.         case discontiguousRange:
  1293.             /* should never happen */
  1294.             break;
  1295.             
  1296.         case simpleCaret:
  1297.             layout->insertionLevel = newLevel;
  1298.             break;
  1299.             
  1300.         case simpleRange:
  1301.         {    SelectionRanges *ranges = &layout->selectionRanges;
  1302.             SelectionOffset startOffset, endOffset;
  1303.             short length;
  1304.         
  1305.             SetEraser(layout);
  1306.             
  1307.             (void) GetRangeSelection(layout->selection, ranges);
  1308.             
  1309.             startOffset = ranges->ranges[0].minOffset;
  1310.             endOffset = ranges->ranges[0].maxOffset;
  1311.             length = endOffset - startOffset;
  1312.             
  1313.             GXSetLayoutParts(
  1314.                 layout->layout,
  1315.                 startOffset,
  1316.                 endOffset,
  1317.                 0,
  1318.                 nil,
  1319.                 nil,
  1320.                 0,
  1321.                 nil,
  1322.                 nil,
  1323.                 1,
  1324.                 &length,
  1325.                 &newLevel);
  1326.                 
  1327.             HideHighlight(layout);
  1328.             DrawDifference(layout);
  1329.             layout->flags |= highlightOutOfDate;
  1330.             ShowHighlight(layout);
  1331.             
  1332.             layout->insertionLevel = -1;
  1333.             break;
  1334.         }
  1335.     }
  1336.  
  1337.     UnlockEditHandle(handle);
  1338. }
  1339.  
  1340. void LayoutEditCut(LayoutEditHandle handle)
  1341. {    LayoutEditPtr layout = LockEditHandle(handle);
  1342.     SelectionType selectionType = GetSelectionType(layout->selection);
  1343.  
  1344.     if (selectionType != emptySelection && selectionType != simpleCaret)
  1345.     {    CopySelection(layout);
  1346.         DeleteSelection(layout);
  1347.         HideHighlight(layout);
  1348.         UpdateLayout(layout);
  1349.         ShowHighlight(layout);
  1350.     }
  1351.     
  1352.     UnlockEditHandle(handle);
  1353. }
  1354.  
  1355. void LayoutEditCopy(LayoutEditHandle handle)
  1356. {    LayoutEditPtr layout = LockEditHandle(handle);
  1357.  
  1358.     CopySelection(layout);
  1359.     
  1360.     UnlockEditHandle(handle);
  1361. }
  1362.  
  1363. void LayoutEditPaste(LayoutEditHandle handle)
  1364. {    LayoutEditPtr layout = LockEditHandle(handle);
  1365.  
  1366.     HideHighlight(layout);
  1367.     PasteSelection(layout);
  1368.     ShowHighlight(layout);
  1369.     
  1370.     UnlockEditHandle(handle);
  1371. }
  1372.  
  1373. void LayoutEditClear(LayoutEditHandle handle)
  1374. {    LayoutEditPtr layout = LockEditHandle(handle);
  1375.  
  1376.     DeleteSelection(layout);
  1377.     HideHighlight(layout);
  1378.     UpdateLayout(layout);
  1379.     ShowHighlight(layout);
  1380.     
  1381.     UnlockEditHandle(handle);
  1382. }
  1383.  
  1384. void LayoutEditFromScrap(LayoutEditHandle handle)
  1385. {    LayoutEditPtr layout = LockEditHandle(handle);
  1386.     long offset, length;
  1387.     Handle buffer = NewHandle(0);
  1388.     
  1389.     if (GetScrap(buffer, 'FLAY', &offset) > 0)
  1390.     {    long portCount = GXGetShapeViewPorts(GXGetDefaultShape(gxLayoutType), nil);
  1391.         gxViewPort *ports = (gxViewPort *) NewPtr(portCount * sizeof(gxViewPort));
  1392.     
  1393.         GXGetShapeViewPorts(GXGetDefaultShape(gxLayoutType), ports);
  1394.         DisposeShapeAt(&layout->scrap);
  1395.     
  1396.         layout->scrap = HandleToShape(buffer, portCount, ports);
  1397.         DisposePtr((Ptr) ports);
  1398.     }
  1399.     else if ((length = GetScrap(buffer, 'TEXT', &offset)) > 0)
  1400.     {    void *text = (void *) LockHandle(buffer);
  1401.         short runLength = length;
  1402.         gxStyle defaultStyle = GXGetShapeStyle(layout->layout);
  1403.         short level0 = 0;
  1404.         
  1405.         DisposeShapeAt(&layout->scrap);
  1406.         layout->scrap = GXNewLayout(
  1407.             1,
  1408.             &runLength,
  1409.             (const void **) &text,
  1410.             1,
  1411.             &runLength,
  1412.             &defaultStyle,
  1413.             1,
  1414.             &runLength,
  1415.             &level0,
  1416.             nil,
  1417.             nil);
  1418.         
  1419.     }
  1420.     
  1421.     DisposeHandle(buffer);
  1422.     
  1423.     UnlockEditHandle(handle);
  1424. }
  1425.  
  1426. void LayoutEditToScrap(LayoutEditHandle handle)
  1427. {    LayoutEditPtr layout = LockEditHandle(handle);
  1428.     
  1429.     ZeroScrap();
  1430.     
  1431.     if (layout->scrap)
  1432.     {    long textLength;
  1433.         Ptr textPtr;
  1434.         Handle shapeHandle = ShapeToHandle(layout->scrap);
  1435.         
  1436.     
  1437.         textLength = GXGetLayout(layout->scrap, nil, nil, nil, nil, nil, nil, nil, nil, nil);
  1438.         textPtr = NewPtr(textLength);
  1439.         GXGetLayout(layout->scrap, (void *) textPtr, nil, nil, nil, nil, nil, nil, nil, nil);
  1440.         
  1441.         PutScrap(GetHandleSize(shapeHandle), 'FLAY', LockHandle(shapeHandle));
  1442.         PutScrap(textLength, 'TEXT', textPtr);
  1443.         
  1444.         DisposeShapeAt(&layout->scrap);
  1445.         DisposePtr(textPtr);
  1446.         DisposeHandle(shapeHandle);
  1447.     }
  1448.     
  1449.     UnlockEditHandle(handle);
  1450. }
  1451.  
  1452.  
  1453. void DisposeLayoutEditHandle(LayoutEditHandle handle)
  1454. {    LayoutEditPtr layout = (LayoutEditPtr) LockHandle(handle);
  1455.  
  1456.     DisposeShapeAt(&layout->layout);
  1457.     DisposeShapeAt(&layout->eraser);
  1458.     DisposeShapeAt(&layout->highlight);
  1459.     DisposeShapeAt(&layout->scrap);
  1460.     DisposeStyleAt(&layout->insertionStyle);
  1461.     DisposeSelection(layout->selection);
  1462.     DisposeHandle(handle);
  1463. }
  1464.